/*
 * XEventBus.java, created on Oct 20, 2005
 * 
 * Copyright (c) 2005 - 2007
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.xfc.eventbus;

import java.util.ArrayList;
import java.util.EventObject;
import java.util.List;

import javax.swing.SwingUtilities;

import org.xfc.XApp;

/**
 *
 *
 * @author Devon Carew
 */
public class XEventBus
{
	private List subscribers	= new ArrayList();
	private List filters 		= new ArrayList();
	
	
	/**
	 * 
	 */
	public XEventBus()
	{
		
	}
	
	/**
	 * 
	 * 
	 * @param event
	 */
	public void publish(final EventObject event)
	{
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				notifySubscribers(event);
			}
		});
	}
	
	/**
	 * 
	 * 
	 * @param subscriber
	 */
	public void subscribe(XSubscriber subscriber)
	{
		subscribe(subscriber, (XEventFilter)null);
	}
	
	/**
	 * 
	 * 
	 * @param subscriber
	 * @param filter
	 */
	public void subscribe(final XSubscriber subscriber, final XEventFilter filter)
	{
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				subscribers.add(subscriber);
				filters.add(filter);
			}
		});
	}
	
	/**
	 * 
	 * 
	 * @param subscriber
	 * @param eventType
	 */
	public void subscribe(XSubscriber subscriber, final Class eventType)
	{
		subscribe(subscriber, new XEventFilter() {
			public boolean accepts(EventObject event) {
				return eventType.isInstance(event);
			}
		});
	}
	
	/**
	 * 
	 * 
	 * @param subscriber
	 */
	public void unsubscribe(final XSubscriber subscriber)
	{
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				removeSubscriber(subscriber);
			}
		});
	}
	
	private void notifySubscribers(EventObject event)
	{
		List notify = new ArrayList();
		
		for (int i = 0; i < subscribers.size(); i++)
		{
			XSubscriber subscriber = (XSubscriber)subscribers.get(i);
			XEventFilter filter = (XEventFilter)filters.get(i);
			
			if (filter == null || filter.accepts(event))
			{
				if (!notify.contains(subscriber))
					notify.add(subscriber);
			}
		}
		
		for (int i = 0; i < notify.size(); i++)
		{
			XSubscriber subscriber = (XSubscriber)notify.get(i);
			
			try
			{
				subscriber.handleEvent(event);
			}
			catch (RuntimeException re)
			{
				XApp.getApp().unhandledException(re);
			}
		}
	}
	
	private void removeSubscriber(XSubscriber subscriber)
	{
		for (int i = subscribers.size() - 1; i >= 0; i--)
		{
			if (subscribers.get(i) == subscriber)
			{
				subscribers.remove(i);
				filters.remove(i);
			}
		}
	}
	
}
